#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "mqtt_client.h"
#include "simple_wifi_sta.h"
#include "uart.h"

static const char* TAG = "mqtt";

#define MQTT_ADDRESS    "******"      // MQTT连接地址
#define MQTT_PORT        ******       // MQTT连接端口号
#define MQTT_CLIENT     "******"      // Client ID（最好自行改一下）
#define MQTT_USERNAME   "******"      // MQTT用户名
#define MQTT_PASSWORD   "******"      // MQTT密码
#define MQTT_BUFFER_SIZE 256
#define MQTT_PUBLIC_TOPIC      "******"     // 推送消息主题,ESP32往这个主题推送消息
#define MQTT_SUBSCRIBE_TOPIC   "******"     // 需要订阅的主题,MQTTX往这个主题推送消息
#define WIFI_CONNECT_BIT BIT0				//定义一个事件组，用于通知main函数WIFI连接成功

// 定义结构体存储解析后的数据
typedef struct {
    int hum1;
    int hum2;
    char ave1[16];
    char cv1[16];
    char ave2[16];
    char cv2[16];
    char ave3[16];
    char cv3[16];
    char ave4[16];
    char cv4[16];
} SensorData;

SensorData data;                                        // 定义结构体变量
static EventGroupHandle_t s_wifi_ev = NULL;             // 定义一个W事件组用于储存WIFI事件
static esp_mqtt_client_handle_t s_mqtt_client = NULL;   // MQTT客户端操作句柄
static bool s_is_mqtt_connected = false;                // MQTT连接标志
static int mqtt_reconnect_count = 0;                    // 重连计数器
static const int MAX_RECONNECT_ATTEMPTS = 10;           // 最大重试次数（可根据需求调整）
static char mqtt_pub_buff[MQTT_BUFFER_SIZE];            // 定义一个静态字符数组作为MQTT发布消息的缓冲区

/**
 * mqtt连接事件处理函数
 * @param event 事件参数
 * @return 无
 */
static void aliot_mqtt_event_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    // 将event_data转换为esp_mqtt_event_handle_t类型
    esp_mqtt_event_handle_t event = event_data;
    // 处理不同的MQTT事件
    switch ((esp_mqtt_event_id_t)event_id){
        case MQTT_EVENT_CONNECTED:{ // 连接成功
            ESP_LOGI(TAG, "mqtt connected");
            s_is_mqtt_connected = true;
            mqtt_reconnect_count = 0;
            esp_mqtt_client_subscribe_single(s_mqtt_client, MQTT_SUBSCRIBE_TOPIC, 1); // 连接成功后，订阅测试主题，QoS等级为1
            break;
        }
        case MQTT_EVENT_DISCONNECTED:{ // 连接断开
            ESP_LOGI(TAG, "mqtt disconnected");
            s_is_mqtt_connected = false;
            if (mqtt_reconnect_count >= MAX_RECONNECT_ATTEMPTS)
            {
                ESP_LOGE(TAG, "Reached max attempts (%d), stop reconnecting", MAX_RECONNECT_ATTEMPTS);
                break;
            }
            mqtt_reconnect_count++; // 重连计数器计数
            ESP_LOGI(TAG, "Reconnect count: %d", mqtt_reconnect_count);
            esp_mqtt_client_stop(s_mqtt_client);
            esp_mqtt_client_start(s_mqtt_client);
            break;
        }
        case MQTT_EVENT_SUBSCRIBED:{ // 收到订阅消息的ACK确认
            ESP_LOGI(TAG, " mqtt subscribed ack, msg_id=%d", event->msg_id);
            break;
        }
        case MQTT_EVENT_UNSUBSCRIBED:{ // 收到解订阅消息的ACK确认
            break;
        }
        case MQTT_EVENT_PUBLISHED:{ // 收到发布消息的ACK确认
            ESP_LOGI(TAG, "mqtt publish ack, msg_id=%d", event->msg_id);
            break;
        }
        case MQTT_EVENT_DATA:{ // 收到MQTT消息数据
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
            printf("DATA=%.*s\r\n", event->data_len, event->data);
            break;
        }
        case MQTT_EVENT_ERROR:{ // 收到MQTT错误事件
            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
            break;
        }
        default:
            break;                      
    }
}

/** 启动mqtt连接
 * @param 无
 * @return 无
*/
void mqtt_init(void)
{
    esp_mqtt_client_config_t mqtt_cfg = {0}; // MQTT连接地址
    // 注册MQTT信息
    mqtt_cfg.broker.address.uri = MQTT_ADDRESS;
    mqtt_cfg.broker.address.port = MQTT_PORT;
    mqtt_cfg.credentials.client_id = MQTT_CLIENT;
    mqtt_cfg.credentials.username = MQTT_USERNAME;
    mqtt_cfg.credentials.authentication.password = MQTT_PASSWORD;
    
    s_mqtt_client = esp_mqtt_client_init(&mqtt_cfg); // 设置mqtt配置，返回mqtt操作句柄
    esp_mqtt_client_register_event(s_mqtt_client, ESP_EVENT_ANY_ID, aliot_mqtt_event_handler, s_mqtt_client); // 注册MQTT事件回调函数
    esp_mqtt_client_start(s_mqtt_client); //启动mqtt连接
}

/** wifi事件通知
 * @param 无
 * @return 无
*/
void wifi_event_handler(WIFI_EV_e ev)
{
    if(ev == WIFI_CONNECTED)
    {
        xEventGroupSetBits(s_wifi_ev,WIFI_CONNECT_BIT);
    }
}

/** 结构体数据填充
 * @param urat_buffer 传入的温度数据 
 * @param data 需要填充的数据结构体
 * @return 无
*/
void parse_uart_buffer(const char *uart_buffer, SensorData *data) 
{
    // 跳过开头的 '@'
    const char *ptr = uart_buffer + 1;
    // 提取 Hum1
    sscanf(ptr, "Hum1:%d", &data->hum1);
    // 查找下一个空格的数据并且将指针移动指针到 Hum2
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 Hum2
    sscanf(ptr, "Hum2:%d", &data->hum2);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 AVE1
    sscanf(ptr, "AVE1:%15[^ ]", data->ave1);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 CV1
    sscanf(ptr, "CV1:%15[^ ]", data->cv1);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 AVE2
    sscanf(ptr, "AVE2:%15[^ ]", data->ave2);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 CV2
    sscanf(ptr, "CV2:%15[^ ]", data->cv2);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 AVE3
    sscanf(ptr, "AVE3:%15[^ ]", data->ave3);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 CV3
    sscanf(ptr, "CV3:%15[^ ]", data->cv3);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 AVE4
    sscanf(ptr, "AVE4:%15[^ ]", data->ave4);
    ptr = strchr(ptr, ' ');
    if (ptr) ptr++;
    // 提取 CV4
    sscanf(ptr, "CV4:%15[^ ]", data->cv4);
}

// MQTT开始函数
void mqtt_start(void *pvParameters)
{
    // 初始化NVS闪存
    esp_err_t ret = nvs_flash_init();
    // 检查NVS初始化是否出错
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }
    // 创建事件组
    s_wifi_ev = xEventGroupCreate();
    EventBits_t ev = 0;

    // 初始化WiFi，传入回调函数。
    wifi_sta_init(wifi_event_handler);

    // 监听WiFi连接事件，WiFi连接成功后，启动MQTT连接
    ev = xEventGroupWaitBits(s_wifi_ev, WIFI_CONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
    if (ev & WIFI_CONNECT_BIT){
        mqtt_init();
    }

    while (1) 
    {
        // 重连监测
        if (mqtt_reconnect_count >= MAX_RECONNECT_ATTEMPTS){
            ESP_LOGW(TAG, "Reconnection stopped, check network or restart device");
            vTaskDelay(pdMS_TO_TICKS(5000));
        }
        else if (s_is_mqtt_connected){ // 如果MQTT已连接，则每隔一段时间发布一条消息到主题
            if(xSemaphoreTake(g_uart_buffer_sem, pdMS_TO_TICKS(3000)) != pdPASS){
                continue;
            }
            parse_uart_buffer(uart_buffer, &data);  // 数据填充解析
            xSemaphoreGive(g_uart_buffer_sem);  // 释放信号量
            // 将数据格式化为 JSON
            snprintf(mqtt_pub_buff, MQTT_BUFFER_SIZE,
             "{\"Hum1\":%d, \"Hum2\":%d, \"AVE1\":\"%s\", \"CV1\":\"%s\", "
             "\"AVE2\":\"%s\", \"CV2\":\"%s\", \"AVE3\":\"%s\", \"CV3\":\"%s\", "
             "\"AVE4\":\"%s\", \"CV4\":\"%s\"}",
             data.hum1, data.hum2,
             data.ave1, data.cv1,
             data.ave2, data.cv2,
             data.ave3, data.cv3,
             data.ave4, data.cv4);

            esp_mqtt_client_publish(s_mqtt_client, MQTT_PUBLIC_TOPIC, mqtt_pub_buff, strlen(mqtt_pub_buff), 1, 0); //1表示Qos质量等级  0表示这个参数是否保留消息
            vTaskDelay(pdMS_TO_TICKS(5000));
        }else{
            vTaskDelay(pdMS_TO_TICKS(200));
        }
    }
    vTaskDelete(NULL); // 实际不会执行到这里
}


